package com.google.code.yargon.ui;

import java.util.EnumSet;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import org.apache.log4j.Logger;

import com.google.code.yargon.util.LogUtil;
import com.google.code.yargon.util.PropertyUtil;

/**
 * Contains key mappings, read from properties<br><br>
 * 
 * How to add new keys:<br>
 * - Add new action to this class, insert it in the enum below, e.g.:<br><br> 
 * 
 * <pre>ACTION_MYACTION ("myaction")}</pre><br><br>
 *   
 * - Add mapping to the property file:<br><br>
 * 
 * <pre>yargon.keymap.myaction = <keycode></pre><br><br>
 *   
 * - Last part of the property name must match the name of the action in the enum action! Multiple keycodes can be mapped to one action, separate by commas.<br>
 * - That's it, keycode can be now used e.g.:<br><br>
 * 
 * <pre>
 * Action action = KeyMap.getAction(keyCode);
 * 
 * if(action == ACTION_UP) {
 *   // walking up
 * }
 * </pre>
 * 
 * Or in switch-case structure. @see AppletWindow#sortKey() for example.
 * 
 * @author Mika Myllynen
 *
 */
public class KeyMap {
	
	/**
	 * Key actions - this enum enables action strings to be bound to enum types
	 * which can then be used in switch-case for example.
	 *  
	 */
	public enum Input {
		
		INPUT_UP				("up"),
		INPUT_UPRIGHT			("upright"),
		INPUT_RIGHT				("right"),
		INPUT_DOWNRIGHT			("downright"),
		INPUT_DOWN				("down"),
		INPUT_DOWNLEFT			("downleft"),
		INPUT_LEFT				("left"),
		INPUT_UPLEFT			("upleft"),
		INPUT_WAIT				("wait"),
		INPUT_USEDOOR			("usedoor"),
		INPUT_SAVE				("save"),
		INPUT_LOAD				("load"),
		INPUT_GODMODE			("godmode"),
		INPUT_UNDEFINED			("undefined");
		
		private final String name;
				
		// Map action names to Actions
		private static final Map<String, Input> mapInput  = new HashMap<String, Input>();
		static {
			for(Input i : EnumSet.allOf(Input.class)) {
				mapInput.put(i.getName(), i);
			}
		}
		
		Input(String name) {
			this.name = name;
		}	
	
		public String getName() {
			return this.name;
		}
		
		public static Input get(String name) {
			return mapInput.get(name);
		}
	}

	private static PropertyUtil props = PropertyUtil.getInstance();
	private static Logger log = LogUtil.getInstance();
	private static HashMap<Integer,String> keyMap = null;
	
	/**
	 * Return input bound to given key code
	 * This will also initialize the keymap on first call
	 * 
	 * @param keyCode
	 * @return
	 */
	public Input getInput(int keyCode) {
		if(null == keyMap) {
			init();
		}
		
		if(keyMap.containsKey(keyCode)) {
			return Input.get(keyMap.get(keyCode));
		}
		
		return Input.INPUT_UNDEFINED;
	}
	
	/**
	 * Initialize key map.
	 * Read all properties that match yargon.keymap.<keyname> and store them
	 * in hash map, using the property value(s) as key(s) and key name as value. 
	 */
	private static void init() {
		keyMap = new HashMap<Integer, String>();
		Properties allProps = props.getProperties();
		Enumeration<?> e = allProps.propertyNames();
		
		log.debug("Reading key mappings.");
		
		// Loop through all properties and look for key mappings
		while(e.hasMoreElements()) {
			String propName = (String) e.nextElement();
			
			// Key may have multiple values separated by commas
			if(propName.matches("yargon.keymap.*")) {
				String keyName = propName.replaceFirst("yargon.keymap.", "");
				String[] keyCodes;
				int keyCode = 0;
				keyCodes = allProps.getProperty(propName).split(",");
				
				// Store all values
				for(int i = 0; i < keyCodes.length; i++) {
					try {
						keyCode = Integer.parseInt(keyCodes[i]);
					} catch(NumberFormatException nfe) {
						log.warn("Illegal keymapping for 'keyName': "+allProps.getProperty(propName));
					}
					keyMap.put(keyCode, keyName);
				}
			}
		}
		
		log.debug(keyMap.size()+" mappings read.");
	}
	
	/**
	 * For debugging purposes, return all used mappings as a string
	 */
	public static String getKeyMap() {
		String str = "";
		
		for(Integer keyCode : keyMap.keySet()) {
			str += "Key '"+keyMap.get(keyCode)+"' mapped to key code: "+keyCode+"\n";
		}
		return str;
	}
}
